package com.blog.blog.service.impl;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.interfaces.Claim;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.blog.blog.dao.mapper.SysUserMapper;
import com.blog.blog.dao.pojo.LoginTicket;
import com.blog.blog.dao.pojo.SysUser;
import com.blog.blog.service.SysUserService;
import com.blog.blog.utils.*;
import com.blog.blog.vo.ErrorCode;
import com.blog.blog.vo.LoginUserVo;
import com.blog.blog.vo.Result;
import com.blog.blog.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class SysUserServiceImpl implements SysUserService, CommunityConstant {

    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    RedisTemplate redisTemplate;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Override
    public SysUser findUserById(Long id) {
        SysUser sysUser = getCache(id);
        if (sysUser == null) {
            sysUser = initCache(id);
            if (sysUser == null) {
                sysUser = new SysUser();
                sysUser.setNickname("");
            }
        }
        return sysUser;
    }

    @Override
    public SysUser findUser(String account, String password) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper();
        wrapper.eq("account", account)
                .eq("password", password)
                .last("limit 1");
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        return sysUser;
    }

    @Override
    public Result getUserInfoByToken(String ticket) {
        /**
         * 1. token合法性校验
         *      是否为空，解析是否成功 redis是否存在
         * 2. 如果校验失败 返回错误
         * 3. 如果成功，返回对应的结果 LoginUserVo
         */
//        Map<String, Claim> checkToken = JWTUtil.checkToken(token);
        if (ticket == null) {
            return Result.fail(ErrorCode.NO_LOGIN.getCode(), ErrorCode.NO_LOGIN.getMsg());
        }
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        LoginTicket loginTicket = (LoginTicket) redisTemplate.opsForValue().get(redisKey);
        if (loginTicket == null){
            return Result.fail(ErrorCode.NO_LOGIN.getCode(),ErrorCode.NO_LOGIN.getMsg());
        }
        SysUser sysUser = findUserById(loginTicket.getUserId());
        LoginUserVo loginUserVo = new LoginUserVo();
        loginUserVo.setAccount(sysUser.getAccount());
        loginUserVo.setNickname(sysUser.getNickname());
        loginUserVo.setId(sysUser.getId());
        loginUserVo.setAvatar(sysUser.getAvatar());
        return Result.success(loginUserVo);
    }

    @Override
    public SysUser findUserByAccount(String account) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq("account", account)
                .last("limit 1");
        return sysUserMapper.selectOne(wrapper);
    }

    @Override
    public void save(SysUser sysUser) {
        sysUserMapper.insert(sysUser);
    }

    @Override
    public UserVo findUserVoById(Long id) {
        SysUser sysUser = sysUserMapper.selectById(id);
        if (sysUser == null) {
            sysUser = new SysUser();
            sysUser.setNickname("");
        }
        UserVo userVo = new UserVo();
        userVo.setId(sysUser.getId());
        userVo.setNickname(sysUser.getNickname());
        userVo.setAvatar(sysUser.getAvatar());
        return userVo;
    }

    public Map<String, Object> getUserInfo() {
        SysUser sysUser = UserThreadLocal.get();
        SysUser user = sysUserMapper.selectById(sysUser.getId());
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        map.put("id", user.getId());
        map.put("nickName", user.getNickname());
        map.put("avatar", user.getAvatar());
        map.put("personalProfile", user.getPersonalProfile());
        return map;
    }

    /**
     * 查询权限
     * @param userId
     * @return
     */
    public Collection<? extends GrantedAuthority> getAuthorities(Long userId) {
        SysUser user = sysUserMapper.selectById(userId);
        ArrayList<GrantedAuthority> list = new ArrayList<>();
        list.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                switch (user.getType()) {
                    case 1:
                        return AUTHORITY_ADMIN;
                    case 2:
                        return AUTHORITY_MODERATOR;
                    default:
                        return AUTHORITY_USER;
                }
            }
        });
        return list;
    }

    @Override
    public LoginTicket findLoginTicket(String ticket) {
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        return (LoginTicket) redisTemplate.opsForValue().get(redisKey);
    }

    /**
     * 登录 (第二版)
     * @param account
     * @param password
     * @param expiredSeconds
     * @param response
     * @return
     */
    @Override
    public Result login(String account, String password, int expiredSeconds, HttpServletResponse response) {
        if (StringUtils.isBlank(account) | StringUtils.isBlank(password)) {
            return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), ErrorCode.PARAMS_ERROR.getMsg());
        }
        SysUser user = findUser(account, password);
        if (user == null) {
            return Result.fail(ErrorCode.ACCOUNT_PWD_NOT_EXIST.getCode(), ErrorCode.ACCOUNT_PWD_NOT_EXIST.getMsg());
        }
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        loginTicket.setTicket(UuidGeneratorUtil.generateUUID());
        loginTicket.setStatus(0);
        loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
        String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
        redisTemplate.opsForValue().set(redisKey, loginTicket, expiredSeconds, TimeUnit.SECONDS);
        //CookieUtil.createTicketCookie(loginTicket.getTicket(), contextPath, expiredSeconds, response);
        return Result.success(loginTicket.getTicket());
    }

    /**
     * 先从缓存中取值
     * @param userId
     * @return
     */
    private SysUser getCache(Long userId) {
        String redisKey = RedisKeyUtil.getUserKey(userId);
        return (SysUser) redisTemplate.opsForValue().get(redisKey);
    }

    /**
     * 初始化缓存数据
     * @param userId
     * @return
     */
    private SysUser initCache(Long userId) {
        SysUser user = sysUserMapper.selectById(userId);
        String redisKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.opsForValue().set(redisKey, user, 3600, TimeUnit.SECONDS);
        return user;
    }

    /**
     * 数据变更时清除缓存数据
     * @param userId
     */
    private void clearCache(Long userId) {
        String redisKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.delete(redisKey);
    }

}